package base.thread_demo.demo08_09;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.locks.LockSupport;

/**
 * 本例演示: unpark 在 park 之前
 * park/unpark 特点
 * 1、wait、notify、notifyAll必须配合Object Monitor一起使用，而park、unpark不必。
 * 2、park、unpark是以线程为单位来阻塞、唤醒线程，而notify随机唤醒一个线程，notifyAll唤醒所有线程。
 * 3、park、unpark可以先 unpark后面即将待park的线程，而wait、notify若 notify在先只会空唤醒一次。
 *
 * park/unpark原理:
 * Java中每个线程都有自己的一个Park对象,由3部分组成:
 * _counter (数量,统计计数,始终最大值是1)好比干粮.unpark时就将该值置为1
 * _cond (条件,阻塞队列)好比休息室.线程park时就进入阻塞队列休息,如果发现没有干粮的话.如果有干粮的话就消耗掉干粮并不进入休息室
 * _mutex(互斥锁,对阻塞队列的引用).
 *
 * unpark()相当于补给干粮,将_counter=1,park()相当于消耗干粮_counter=0
 *
 *
 */
public class ParkAndUnparkDemo1 {

    private static final Logger log = LoggerFactory.getLogger(ParkAndUnparkDemo1.class);

    public static void main(String[] args) {
        Thread t1 = new Thread(()->{
            log.info("{} start...", Thread.currentThread().getName());
            try {
                Thread.sleep(3000);// 休眠3s后去执行 park阻塞
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            log.info("{} park...", Thread.currentThread().getName());
            LockSupport.park();
            log.info("{} resume...", Thread.currentThread().getName());
        },"t1");
        t1.start();

        // main线程立马去unpark t1线程(主线程可以先unpark线程t1,即使t1还未park住)
        log.info("{} unpark t1", Thread.currentThread().getName());
        LockSupport.unpark(t1);
    }
}
